#include<arm_neon.h>
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<sys/time.h>
#include<math.h>
using namespace std;


string getbeiAddr(int which)
{
    switch (which) {
    case 1:
        return "/home/sTest/2110935/data/Groebner/1_130_22_8/2.txt";
    case 2:
        return "/home/sTest/2110935/data/Groebner/2_254_106_53/2.txt";
    case 3:
        return "/home/sTest/2110935/data/Groebner/3_562_170_53/2.txt";
    case 4:
        return "/home/sTest/2110935/data/Groebner/4_1011_539_263/2.txt";
    case 5:
        return "/home/sTest/2110935/data/Groebner/5_2362_1226_453/2.txt";
    case 6:
        return "/home/sTest/2110935/data/Groebner/6_3799_2759_1953/2.txt";
    case 7:
        return "/home/sTest/2110935/data/Groebner/7_8399_6375_4535/2.txt";
    case 8:
        return "/home/sTest/2110935/data/Groebner/8_23045_18748_14325/2.txt";
    case 9:
        return "/home/sTest/2110935/data/Groebner/9_37960_29304_14921/2.txt";
    case 10:
        return "/home/sTest/2110935/data/Groebner/10_43577_39477_54274/2.txt";
    case 11:
        return "/home/sTest/2110935/data/Groebner/11_85401_5724_756/2.txt";
    default:
        return "";
    }
}
string getziAddr(int which)
{
    switch (which) {
    case 1:
        return "/home/sTest/2110935/data/Groebner/1_130_22_8/1.txt";
    case 2:
        return "/home/sTest/2110935/data/Groebner/2_254_106_53/1.txt";
    case 3:
        return "/home/sTest/2110935/data/Groebner/3_562_170_53/1.txt";
    case 4:
        return "/home/sTest/2110935/data/Groebner/4_1011_539_263/1.txt";
    case 5:
        return "/home/sTest/2110935/data/Groebner/5_2362_1226_453/1.txt";
    case 6:
        return "/home/sTest/2110935/data/Groebner/6_3799_2759_1953/1.txt";
    case 7:
        return "/home/sTest/2110935/data/Groebner/7_8399_6375_4535/1.txt";
    case 8:
        return "/home/sTest/2110935/data/Groebner/8_23045_18748_14325/1.txt";
    case 9:
        return "/home/sTest/2110935/data/Groebner/9_37960_29304_14921/1.txt";
    case 10:
        return "/home/sTest/2110935/data/Groebner/10_43577_39477_54274/1.txt";
    case 11:
        return "/home/sTest/2110935/data/Groebner/11_85401_5724_756/1.txt";
    default:
        return "";
    }
}
int getHang(int which)
{
    switch (which)
    {
    case 1:
        return 8;
    case 2:
        return 53;
    case 3:
        return 53;
    case 4:
        return 263;
    case 5:
        return 453;
    case 6:
        return 1953;
    case 7:
        return 4535;
    case 8:
        return 14325;
    case 9:
        return 14291;
    case 10:
        return 54274;
    case 11:
        return 756;
    default:
        return 0;
    }
}
int getLie(int which)
{
    switch (which)
    {
    case 1:
        return 130;
    case 2:
        return 254;
    case 3:
        return 562;
    case 4:
        return 1011;
    case 5:
        return 2362;
    case 6:
        return 3799;
    case 7:
        return 8399;
    case 8:
        return 23075;
    case 9:
        return 37960;
    case 10:
        return 43577;
    case 11:
        return 85401;
    default:
        return 0;
    }
}



void showLie(unsigned int* m, int lie)
{
    for (int i = 0; i < lie; i++)
    {
        cout << m[i] << " ";
    }
    cout << endl;
}
unsigned int** init(int hang, int lie)
{
    unsigned int** m = new unsigned int* [hang];
    for (int i = 0; i < hang; i++)
    {
        m[i] = new unsigned int[lie];
        for (int p = 0; p < lie; p++)
        {
            m[i][p] = 0;
        }
    }
    return m;
}
int qujian(int nowliePos, int lie)
{
    return (lie - nowliePos - 1) / 32;
}
int liePos(int nowliePos, int lie)
{
    return lie - (((lie - nowliePos - 1) / 32) * 32 + nowliePos) - 1;
}
unsigned int bit2int(int* m)
{
    unsigned int result = 0;
    for (int i = 0; i < 32; i++)
    {
        if (m[i])result += pow(2, 31 - i);
    }
    return result;
}
void showM(unsigned int** m, int hang, int lie)
{
    for (int i = 0; i < hang; i++)
    {
        showLie(m[i], lie);
        cout << endl;
    }
}
int* int2bit(unsigned int decimal_num)
{
    int* pos = new int[32];
    unsigned int mask = 1 << 31;
    for (int i = 0; i < 32; i++) {
        if ((decimal_num & mask) == 0) {
            pos[i] = 0;
        }
        else {
            pos[i] = 1;
        }
        mask = mask >> 1;
    }
    return pos;
}
unsigned int** write(string beiAddr, int beihang, int beilie)
{
    int lie = (beilie / 32 * 32 == beilie) ? beilie / 32 : beilie / 32 + 1;
    int yu = lie - beilie;
    unsigned int** m = new unsigned int* [beihang];
    for (int i = 0; i < beihang; i++)
    {
        m[i] = new unsigned int[lie];
        for (int p = 0; p < lie; p++)
            m[i][p] = 0;
    }
    ifstream fin;
    fin.open(beiAddr.c_str(), ios::in);
    int* pos = new int[32];
    for (int i = 0; i < 32; i++)
        pos[i] = 0;
    char ch;
    int temp = 0, nowPos = 0, bitclimiter = 0, whetherBegin = 1, nowQujian = 0, lastQujian = 0;
    while (fin.get(ch))
    {
        if (ch >= '0' && ch <= '9')
        {
            temp *= 10;
            temp += ch - '0';
        }
        else if (ch == ' ')
        {
            if (whetherBegin)
            {
                lastQujian = qujian(temp, beilie);
                bitclimiter = liePos(temp, beilie);
                pos[bitclimiter] = 1;
                whetherBegin = 0;
            }
            else
            {
                nowQujian = qujian(temp, beilie);
                if (nowQujian != lastQujian)
                {
                    m[nowPos][lastQujian] = bit2int(pos);
                    for (int i = 0; i < 32; i++)
                        pos[i] = 0;
                }
                bitclimiter = liePos(temp, beilie);
                pos[bitclimiter] = 1;
                lastQujian = nowQujian;
            }
            temp = 0;
        }
        else if (ch == '\n')
        {
            m[nowPos][lastQujian] = bit2int(pos);
            for (int i = 0; i < 32; i++)
                pos[i] = 0;
            whetherBegin = 1;
            nowPos++;
            temp = 0;
            nowQujian = 0;
            lastQujian = 0;
        }
    }
    fin.close();
    return m;
}


streampos UpdateZi(unsigned** zi, int howmany, int zilie, int lie, int beginHang, ifstream& fin, streampos headPos)
{
    int pos[32];
    for (int i = 0; i < howmany; i++)
        for (int p = 0; p < lie; p++)
            zi[i][p] = 0;
    for (int i = 0; i < 32; i++)
        pos[i] = 0;
    streampos nowHead = headPos;
    fin.seekg(headPos);
    char ch;
    int temp = 0, nowPos = 0, bitclimiter = 0, whetherBegin = 1, nowQujian = 0, lastQujian = 0, thisishang = 0, dotimes = 0;
    while (dotimes < howmany && fin.get(ch))
    {
        if (ch >= '0' && ch <= '9')
        {
            temp *= 10;
            temp += ch - '0';
        }
        else if (ch == ' ')
        {
            if (whetherBegin)
            {
                if (temp < beginHang - howmany)
                {
                    break;
                }
                else
                {
                    lastQujian = qujian(temp, zilie);
                    bitclimiter = liePos(temp, zilie);
                    pos[bitclimiter] = 1;
                    whetherBegin = 0;
                    thisishang = beginHang - temp - 1;
                }
            }
            else
            {
                nowQujian = qujian(temp, zilie);
                if (nowQujian != lastQujian)
                {
                    zi[thisishang][lastQujian] = bit2int(pos);
                    for (int i = 0; i < 32; i++)
                        pos[i] = 0;
                }
                bitclimiter = liePos(temp, zilie);
                pos[bitclimiter] = 1;
                lastQujian = nowQujian;
            }
            temp = 0;
        }
        else if (ch == '\n')
        {
            nowHead = fin.tellg();
            zi[thisishang][lastQujian] = bit2int(pos);
            for (int i = 0; i < 32; i++)
                pos[i] = 0;
            whetherBegin = 1;
            dotimes++;
            temp = 0;
            nowQujian = 0;
            lastQujian = 0;
        }
    }
    return nowHead;
}
int findinthead(unsigned int num, int lie, int qujian)
{
    int* pos = int2bit(num);
    for (int i = 0; i < 32; i++)
    {
        if (pos[i])
        {
            return lie - qujian * 32 - i - 1;
        }
    }
    return -1;
}
int findHead(unsigned int* m, int lie)
{
    for (int i = 0; i < lie; i++)
    {
        if (m[i])
        {
            return findinthead(m[i], lie, i);
        }
    }
    return -1;
}


bool isNotNull(unsigned int* m, int lie)
{
    for (int i = 0; i < lie; i++)
    {
        if (m[i])
        {
            return 1;
        }
    }
    return 0;
}
void AsubB(unsigned int* a, unsigned int* b, int lie)
{
    for (int i = 0; i < lie; i++)
    {
        a[i] = a[i] ^ b[i];
    }
}
void bingxingAsubB(unsigned int* a, unsigned int* b, int lie)
{
    int i = 0;
    uint32x4_t t1, t2;
    for (i = 0; i + 4 < lie; i += 4)
    {
        t1 = vld1q_u32(&a[i]);
        t2 = vld1q_u32(&b[i]);
        t1 = veorq_u32(t1, t2);
        vst1q_u32(&a[i], t1);
    }

    for (; i < lie; i++)
    {
        a[i] = (a[i] == b[i]) ? 0 : 1;
    }


}

void testShow(unsigned int** m, int hang, int lie, int lieOf01)
{
    int* temp;
    for (int i = 0; i < hang; i++)
    {
        for (int p = 0; p < lie; p++)
        {
            temp = int2bit(m[i][p]);
            for (int q = 0; q < 32; q++)
            {
                if (temp[q])
                {
                    cout << lieOf01 - 32 * p - q - 1 << " ";
                }
            }
        }
        cout << endl;
    }
}
double common(unsigned** bei, int howmany, int beihang, int beilie, int zihang, int zilie, int whichTextIsNow, int bingOrCom)
{
    struct timeval t1, t2;
    double timeuse = 0;
    string ziAddr = getziAddr(whichTextIsNow);
    ifstream fin;
    fin.open(ziAddr.c_str(), ios::in);
    int lie = (beilie / 32 * 32 == beilie) ? beilie / 32 : beilie / 32 + 1;
    unsigned int** zi = init(howmany, lie);
    int beginHang = zihang;
    int times = zihang / howmany;
    streampos headPos = 0;
    bool* wetherThisHangIsOk = new bool[beihang];
    for (int i = 0; i < beihang; i++)
        wetherThisHangIsOk[i] = 0;
    int nowHead = 0, ziHead = 0;
    for (int cycles = 0; cycles < times; cycles++)
    {
        beginHang = zihang - cycles * howmany;
        headPos = UpdateZi(zi, howmany, zilie, lie, beginHang, fin, headPos);
        gettimeofday(&t1, NULL);
        for (int beiPos = 0; beiPos < beihang; beiPos++)
        {
            if (wetherThisHangIsOk[beiPos])
            {
                continue;
            }
            for (int ziPos = beginHang - 1; ziPos >= beginHang - howmany; ziPos--)
            {
                nowHead = findHead(bei[beiPos], zilie);
                if (nowHead >= beginHang - howmany && nowHead < beginHang)
                {
                    if (isNotNull(zi[beginHang - nowHead - 1], lie))
                    {
                        if (bingOrCom) bingxingAsubB(bei[beiPos], zi[beginHang - nowHead - 1], lie);
                        else AsubB(bei[beiPos], zi[beginHang - nowHead - 1], lie);
                    }
                    else
                    {
                        wetherThisHangIsOk[beiPos] = 1;
                        for (int qqq = 0; qqq < lie; qqq++)
                        {
                            zi[beginHang - nowHead - 1][qqq] = bei[beiPos][qqq];
                        }
                        break;
                    }
                }
                else break;
            }
        }
        gettimeofday(&t2, NULL);
        timeuse += (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec) / 1000000.0;
    }
    return timeuse;
}

int main()
{
    for (int i = 9; i <= 9; i++)
    {
        int beihang, beilie, zihang, zilie;
        int whichTextIsNow = i;
        beihang = getHang(whichTextIsNow);
        beilie = zihang = zilie = getLie(whichTextIsNow);
        string beiAddr = getbeiAddr(whichTextIsNow);
        unsigned int** bei = write(beiAddr, beihang, beilie);

        int howmany = 200;

        double time = common(bei, howmany, beihang, beilie, zihang, zilie, whichTextIsNow, 0);
        cout << time << endl;
    }
    return 0;
}
